/*
-----------------------------------------------------------------------------
This source file is part of Labor3D
(Labor 3D Graphics Engine)

Copyright (c) 2009-2020 Rock Mao
* creator : Rock Mao
* created : 2009-5-3   22:29
* filename: LaborPoint3.h
-----------------------------------------------------------------------------
*/
#ifndef __XVECTOR_3D_INLINE_INCLUDE__
#define __XVECTOR_3D_INLINE_INCLUDE__

#include "../LaborCoreDef.h"
#include "xmathfunc.h"
#include "LaborTypes.h"
NAMESPACE_LABOR3D_BEGIN
#pragma  pack (push,4)

template <typename _Type> class  TPoint3
{
public:
typedef _Type value_type ;
public:
	TPoint3(){};
	TPoint3(_Type _v){	x = _v ; y = _v; z = _v; }
	TPoint3(_Type _x,_Type _y ,_Type _z){	x = _x ; y = _y; z = _z;}
	TPoint3(TPoint2<_Type>& v){	x = v.x ; y = v.y ;z = 0 ;}
	TPoint3(TPoint4<_Type> & v){	x = v.x ; y = v.y ;z = v.z;}
	//TPoint3(TPoint3<_Type> & v){	x = v.x ; y = v.y ;z = v.z;}

	//-----------------------------------------------------
	//
	//-----------------------------------------------------
	void        add(const TPoint3<_Type>& rv)
	{
		x += rv.x; y += rv.y; z += rv.z;
	}


	void        sub(const TPoint3<_Type>& rv)
	{
		x -= rv.x; y -= rv.y; z -= rv.z;
	}

	//-----------------------------------------------------
	//
	//-----------------------------------------------------
	void        mul(lscalar s)
	{
		x = _Type(x *s); 
		y = _Type(y *s); 
		z = _Type(z *s);
	}


	//-----------------------------------------------------
	//
	//-----------------------------------------------------
	void        normalize()
	{
		lscalar len = (lscalar)xsqrt( lscalar(x * x + y * y + z * z) ) ; 
		x=_Type(x/len);
		y=_Type(y/len); 
		z=_Type(z/len);
	}


	//-----------------------------------------------------
	//
	//-----------------------------------------------------
	void        normalize(TPoint3<_Type> &vout)
	{
		lscalar len = (lscalar)xsqrt( lscalar(x * x + y * y + z * z) ) ; 
		vout.x = _Type(x/len); 
		vout.y = _Type(y/len); 
		vout.z = _Type(z/len);
	};

	//-----------------------------------------------------
	//
	//-----------------------------------------------------
	TPoint3<_Type>    operator +(const TPoint3<_Type>& v)  const     
	{ 
		return TPoint3<_Type>(v.x + x, v.y + y,v.z + z);
	}

	//-----------------------------------------------------
	//
	//-----------------------------------------------------
	TPoint3<_Type>    operator -(const TPoint3<_Type>& v)  const     
	{ 
		return TPoint3<_Type>(x - v.x, y - v.y,z - v.z);
	}


	//-----------------------------------------------------
	//
	//-----------------------------------------------------
	TPoint3<_Type>    operator *(const lscalar s)  const     
	{ 
		return TPoint3<_Type>( _Type(x * s), _Type(y * s) , _Type(z * s) );
	}

	//-----------------------------------------------------
	//
	//-----------------------------------------------------
	TPoint3<_Type>    operator /(const lscalar s)  const     
	{ 
		return TPoint3<_Type>( _Type(x / s), _Type(y / s) , _Type(z / s) );
	}
	//-----------------------------------------------------
	//
	//-----------------------------------------------------
	bool         operator ==(const TPoint3<_Type>& v)   const     
	{
		return (v.x == x && v.y == y && v.z == z) ; 
	}
	//-----------------------------------------------------
	//
	//-----------------------------------------------------
	bool         operator >(const TPoint3<_Type>& v)   const     
	{
		return (v.x > x && v.y > y && v.z > z) ; 
	}
	//-----------------------------------------------------
	//
	//-----------------------------------------------------
	bool         operator <(const TPoint3<_Type>& v)   const     
	{
		return (v.x < x && v.y < y && v.z < z) ; 
	}
	//-----------------------------------------------------
	//the lenght of a vector
	//-----------------------------------------------------
	value_type        fabs()  const     
	{ 
		return (value_type)xsqrt( lscalar(x * x + y * y + z * z) ) ;
	}

	//-----------------------------------------------------
	//
	//-----------------------------------------------------
	value_type        length()  const     
	{ 
		return (value_type)xsqrt( lscalar(x * x + y * y + z * z) );
	}



	//-----------------------------------------------------
	//
	//-----------------------------------------------------
	value_type        squardlen()  const     
	{
		return (value_type)(x * x + y * y + z * z) ;
	}


	//! Computes distance to another CLPoint3
	value_type	distance(const TPoint3<_Type>& b)			const
	{
		return value_type( sqrtf((x - b.x)*(x - b.x) + (y - b.y)*(y - b.y) + (z - b.z)*(z - b.z)));
	}

	//! Computes square distance to another CLPoint
	value_type			squareDistance(const TPoint3<_Type>& b)		const
	{
		return value_type ((x - b.x)*(x - b.x) + (y - b.y)*(y - b.y) + (z - b.z)*(z - b.z));
	}

	//-----------------------------------------------------
	//dot product
	//-----------------------------------------------------
	value_type        dot(const TPoint3<_Type>& v)  const     
	{
		return value_type(v.x*x + v.y *y + v.z * z ); 
	}


	//-----------------------------------------------------
	//cross product
	//-----------------------------------------------------
	void         cross(const TPoint3<_Type>& v,TPoint3<_Type>& vOut)  const     
	{
		vOut.x = y * v.z - v.y * z;
		vOut.y = z * v.x - v.z * x;
		vOut.z = x * v.y - v.x * y;
	}

	//-----------------------------------------------------
	//cross product
	//-----------------------------------------------------
	TPoint3<_Type>      cross(const TPoint3<_Type>& v)  const     
	{
		_Type nx = y * v.z - v.y * z;
		_Type ny = z * v.x - v.z * x;
		_Type nz = x * v.y - v.x * y;
		return TPoint3<_Type>(nx,ny,nz);
	}

	TPoint3<_Type>&     operator +=(const TPoint3<_Type>& v)
	{ 
		x += v.x ;
        y += v.y ; 
        z += v.z;
		return *this; 
	}

	//! Assignment from values
	TPoint3<_Type>&			set(_Type _x, _Type _y, _Type _z)		{ x  = _x;		y  = _y;	z  = _z;			return *this;	}

	//-----------------------------------------------------
	//
	//-----------------------------------------------------
	TPoint3<_Type>&     operator -=(const TPoint3<_Type>& v)
	{ 
		x -= v.x ; 
        y -= v.y ; 
        z -= v.z;
		return *this; 
	}

	//-----------------------------------------------------
	//
	//-----------------------------------------------------
	TPoint3<_Type>&     operator *=(value_type s)
	{ 
		x = _Type(x *s); 
		y = _Type(y *s); 
		z = _Type(z *s); 
		return *this; 
	}

	//! Operator for CLPoint Scale = float * CLPoint.
	friend	TPoint3<_Type> 	operator*(value_type s, const TPoint3<_Type> & p)				{ return TPoint3<_Type> (s * p.x, s * p.y, s * p.z);			}

	//-----------------------------------------------------
	//
	//-----------------------------------------------------
	TPoint3<_Type>      operator ^(const TPoint3<_Type>& v)  const     
	{ 
		return cross(v); 
	}


	//-----------------------------------------------------
	//
	//-----------------------------------------------------
	value_type operator |(const TPoint3<_Type>& v1)  const     
	{
		value_type t = dot(v1)/(fabs() * v1.fabs());
		return (_Type)XM_ACosD((lscalar)t);
	}

	//-----------------------------------------------------
	//
	//-----------------------------------------------------
	value_type operator [] ( int idx )    const   
	{
		return v[idx];
	}

	//-----------------------------------------------------
	//
	//-----------------------------------------------------
	bool operator||(const TPoint3<_Type>& v1)  const     
	{
		_Type x = y * v1.z - v1.y * z;
		_Type y = z * v1.x - v1.z * x;
		_Type z = x * v1.y - v1.x * y;

		if(numeric_equal(x, (_Type)0) && numeric_equal(y,(_Type)0) && numeric_equal(z,(_Type)0))
			return true;
		else
			return false;
	}

	//-----------------------------------------------------
	//
	//-----------------------------------------------------
	//! Unary operator for CLPoint Negate = - CLPoint
	inline	TPoint3	<_Type>		operator-()							const		{ return TPoint3<_Type>(-x, -y, -z); }

	//-----------------------------------------------------
	//
	//-----------------------------------------------------
	value_type clamp(TPoint3<_Type>& v1)  const     
	{
		value_type t = dot(v1)/(fabs() * v1.fabs());

		return (value_type)XM_ACosD((lscalar)t);
	}

	//! Computes square magnitude
	inline	float			squareMagnitude()	const		{ return x*x + y*y + z*z;												}
	//! Computes magnitude
	inline	float			magnitude()			const		{ return sqrtf(x*x + y*y + z*z);										}
	//! Computes volume
	inline	float			volume()			const		{ return x * y * z;														}

		/** Calculates a reflection vector to the plane with the given normal . 
	@remarks NB assumes 'this' is pointing AWAY FROM the plane, invert if it is not.
	*/
	inline	TPoint3	<_Type> reflect(const TPoint3	<_Type>& normal)
	{
		return TPoint3	<_Type>( *this - ( 2 * this->dot(normal) * normal ) );
	}
	//-----------------------------------------------------
	//
	//-----------------------------------------------------
	bool isZero()  const     
	{
		return (fabs()<0.000000001f);
	}

	//! Returns MIN(x, y, z);
	inline	float			Min()				const			{ return MIN(x, MIN(y, z));												}
	//! Returns MAX(x, y, z);
	inline	float			Max()				const			{ return MAX(x, MAX(y, z));												}

	//! Sets each element to be componentwise minimum
	inline	TPoint3	<_Type>&			Min(const TPoint3	<_Type>& p)				{ x = MIN(x, p.x); y = MIN(y, p.y); z = MIN(z, p.z);	return *this;	}
	//! Sets each element to be componentwise maximum
	inline	TPoint3	<_Type>&			Max(const TPoint3	<_Type>& p)				{ x = MAX(x, p.x); y = MAX(y, p.y); z = MAX(z, p.z);	return *this;	}


	//! Clears the vector
	inline	TPoint3<_Type>&			zero()									{ x =			y =			z = 0.0f;			return *this;	}

	//! Checks CLPoint validity
	inline	bool			isValid()			const
	{
		if(!isValidFloat(x))	return false;
		if(!isValidFloat(y))	return false;
		if(!isValidFloat(z))	return false;
		return true;
	}
	operator _Type* (){ return v ; }

public:
	union
	{
		struct
		{
			_Type x,y,z;
		};
		_Type   v[3];
	};

};

template <typename T> TPoint3<T> operator * (const T& v1 , const TPoint3<T>& v2)
{
    TPoint3<T> _ret;
    _ret.x = v1 * v2.x;
    _ret.y = v1 * v2.y;
    _ret.z = v1 * v2.z;
    return _ret;
}

template <typename T> TPoint3<T> operator * (const TPoint3<T>& v1 , const TPoint3<T>& v2)
{
    TPoint3<T> _ret;
    _ret.x = v1.x * v2.x;
    _ret.y = v1.y * v2.y;
    _ret.z = v1.z * v2.z;
    return _ret;
}



template <typename T> class  xtriidx
{
public:
    union 
    {
        struct 
        {
            T  v1;
            T  v2;
            T  v3;
        };
        T   v[3];
    };

    void swapHand()
    {
        T _t = v3;
        v3 = v1;
        v1 = _t;
    }

    xtriidx& operator = (const TPoint3<T>& rhv)
    {
        v[0] = rhv.x;
        v[1] = rhv.y;
        v[2] = rhv.z;
    }
};
#pragma pack(pop)


NAMESPACE_LABOR3D_END

#endif

